from datetime import datetime
import time

from sqlalchemy import func, and_

from app.api.admin.fields import admin_user_fields, order_fields, attr_fields, attr_value_fields
from app.api.admin.parsers import admin_login_args, recharge_args, check_order_args, get_branch_orders_args, \
    modify_admin_user_password_args, pagination_parser, change_admin_user_password_args, get_param_parser, \
    order_filter_parser, date_filter_parser, add_attr_args, update_infos_args
from app.exception import APIException, USER_NOT_EXISTS, ORDER_NOT_EXISTS, NOT_ALLOWED_EXCHANGE, \
    ORDER_ALREADY_PROCESSED, DATABASE_ERROR, USER_IS_LOCKED, USERNAME_OR_PASSWORD_WRONG, DOLL_IS_LIMITED, \
    GOODS_NOT_ONLINE, GOODS_NOT_EXISTS, ATTR_ALREADY_EXISTS, ATTR_NOT_EXISTS, ATTR_VALUE_ALREADY_EXISTS
from app.models import AdminUser, User, UserRecord, Order, Goods, GoodsInfo, GoodsRecord, GoodsSkuStock, Attribute, \
    AttributeValue
from app.extensions import auth, roles_accepted, db
# from app.extensions import scheduler
from flask_restful import marshal
from flask import jsonify, g, current_app
from qiniu import Auth as QiniuAuth


def login():
    args = admin_login_args.parse_args()
    admin_user = AdminUser.query.filter_by(username=args['username']).first()
    if admin_user and admin_user.locked is True:
        # return jsonify({'coed': -1, 'message': '账号已被冻结'})
        raise APIException(USER_IS_LOCKED)
    if admin_user and admin_user.verify_password(args['password']):
        data = marshal(admin_user, admin_user_fields)
        return jsonify({
            'code': 0,
            'message': '',
            'token': admin_user.generate_auth_token(),
            'userInfo': data
        }), 200
    else:
        # return jsonify({'code': -1, 'message': '用户名或密码错误'}), 200
        raise APIException(USERNAME_OR_PASSWORD_WRONG)


def logout():
    pass


def change_password():
    """ 未登录修改密码 """
    args = change_admin_user_password_args.parse_args()
    admin_user = AdminUser.query.filter_by(username=args['username']).first()
    if admin_user is None:
        # return jsonify({'coed': -1, 'message': '用户不存在'})
        raise APIException(USER_NOT_EXISTS)
    if admin_user and admin_user.locked is True:
        # return jsonify({'coed': -1, 'message': '账号已被冻结'})
        raise APIException(USER_IS_LOCKED)
    old_password = args.get('old_password')
    if not admin_user.verify_password(old_password):
        raise APIException(USERNAME_OR_PASSWORD_WRONG)
    password = args.pop('password')
    if password:
        admin_user.set_password(password)
    admin_user.update(True, )
    return jsonify({
        'code': 0,
        'message': '修改密码成功'
    }), 200


@auth.login_required
def get_me():
    return jsonify({
        'code': 0,
        'data': marshal(g.user, admin_user_fields)
    }), 200


@auth.login_required
def modify_password():
    """ 修改密码 """
    user = g.user
    # if user.id != user_id:
    #     raise APIException('没有权限')
    args = modify_admin_user_password_args.parse_args()
    old_password = args.get('old_password')
    if not user.verify_password(old_password):
        raise APIException('原密码错误')
    password = args.pop('password')
    if password:
        user.set_password(password)
    user.update(True, )
    return jsonify({
        'code': 0,
        'message': '修改密码成功'
    }), 200


@auth.login_required
def get_qiniu_token():
    access_key = current_app.config['QINIU_ACCESS_KEY']
    secret_key = current_app.config['QINIU_SECRET_KEY']

    # 构建鉴权对象
    q = QiniuAuth(access_key, secret_key)
    # 要上传的空间
    bucket_name = 'img-zhuawawa'
    # 上传到七牛后保存的文件名
    key = None
    # 生成上传 Token，可以指定过期时间等
    # 上传策略示例
    # https://developer.qiniu.com/kodo/manual/1206/put-policy
    policy = {
        # 'callbackUrl':'https://requestb.in/1c7q2d31',
        # 'callbackBody':'filename=$(fname)&filesize=$(fsize)'
        # 'persistentOps':'imageView2/1/w/200/h/200'
    }
    # 3600为token过期时间，秒为单位。3600等于一小时
    token = q.upload_token(bucket_name, key, 3600, policy)
    data = {
        'bucketHost': 'https://static.bianfuyule.com/',
        'key': key,
        'token': token,
    }
    return jsonify({
        'code': 0,
        'data': data
    }), 200


@auth.login_required
@roles_accepted('manager')
def recharge():
    args = recharge_args.parse_args()
    admin_user = g.user
    user_id = args.get('user_id')
    doll = args.get('doll')
    # user = User.query.get(user_id)
    user = User.query.filter_by(uid=user_id).first()
    if not user:
        raise APIException(USER_NOT_EXISTS)
    if doll > 100:
        raise APIException(DOLL_IS_LIMITED)
    sql = "SELECT SUM(doll) FROM t_user_record WHERE type=1 AND user_id=%s" % (user.uid)
    sql += " AND DATE_FORMAT(created,'%Y%m%d') = DATE_FORMAT(CURDATE(),'%Y%m%d')"
    result = db.session.execute(sql)
    row = result.fetchone()[0]
    if row:
        column = 300 - row
        if doll > column:
            raise APIException(DOLL_IS_LIMITED)
    user.doll += doll
    if user.branch_id == 0:
        user.branch_id = admin_user.branch_id
    user.update(False, )
    record_row = {
        'user_id': user.id,
        'type': 1,
        'doll': doll,
        'operate_id': admin_user.id,
        'branch_id': admin_user.branch_id
    }
    UserRecord.create(False, **record_row)
    try:
        db.session.commit()
    except Exception as e:
        db.session.rollback()
        raise APIException(DATABASE_ERROR)
    return jsonify({
        'code': 0,
        'message': '存娃娃成功',
        'data': {}
    }), 200


@auth.login_required
@roles_accepted('manager')
def check_order(order_id):
    order = Order.query.get(order_id)
    if not order:
        raise APIException(ORDER_NOT_EXISTS)
    if order.status != 0:
        raise APIException(ORDER_ALREADY_PROCESSED)
    admin_user = g.user
    if order.branch_id != admin_user.branch_id:
        raise APIException(NOT_ALLOWED_EXCHANGE)
    user = User.query.get(order.user_id)
    args = check_order_args.parse_args()
    check = args.get('check')
    if check:
        order.status = 3
        record = UserRecord.query.filter(
            and_(UserRecord.created == order.created, UserRecord.user_id == user.id)).first()
        if record:
            record.operate_id = admin_user.id
            record.update(False, )
    else:
        order.status = 4
        # 拒绝 娃娃加回去
        user.doll += order.total_price
        user.update(False, )
        # 拒绝 已换减回去
        goods = Goods.query.get(order.goods_id)
        goods.total_num -= order.amount
        goods.update(False, )
        info = GoodsInfo.query.filter_by(goods_id=order.goods_id, branch_id=order.branch_id).first()
        info.exchange_num -= order.amount
        # 拒绝 库存加回去
        info.stock += order.amount
        info.is_listing = 1
        info.update(False, )
        # 插入商品库存变更记录
        stock_row = {
            'stock_id': info.id,
            'type': 2,
            'increment': order.amount
        }
        GoodsRecord.create(False, **stock_row)
        # 插入用户娃娃变更记录
        record_row = {
            'user_id': user.id,
            'type': 3,
            'doll': order.total_price,
            'operate_id': admin_user.id,
            'branch_id': order.branch_id
        }
        UserRecord.create(False, **record_row)
    order.update(False, )

    try:
        db.session.commit()
    except Exception as e:
        db.session.rollback()
        raise APIException(DATABASE_ERROR)

    return jsonify({
        'code': 0,
        'message': '成功',
        'data': {}
    }), 200


@auth.login_required
@roles_accepted('manager')
def get_branch_orders():
    args = get_branch_orders_args.parse_args()
    user_id = args.get('user_id')
    status = args.get('status')
    admin_user = g.user
    query = Order.query.filter_by(branch_id=admin_user.branch_id, exchange_type=0)
    if user_id:
        query = query.filter_by(user_id=user_id)
    if status == 0:
        query = query.filter_by(status=status)
    elif status == 1:
        query = query.filter(Order.status > 0)
    query = query.order_by(Order.id.desc())

    page_args = pagination_parser.parse_args(req=args)
    page = page_args.get('page')
    per_page = page_args.get('per_page')

    _orders = query.paginate(page, per_page=per_page, error_out=False)

    orders = {
        'data': marshal(_orders.items, order_fields),
        "pageSize": _orders.per_page,
        "pageNo": _orders.page,
        "totalPage": _orders.pages,
        "totalCount": _orders.total
    }

    return jsonify({
        'code': 0,
        'message': '成功',
        'data': orders
    }), 200


@auth.login_required
@roles_accepted('admin')
def export_orders():
    args = get_param_parser.parse_args()

    query = Order.query

    _filter = args.get('filter')
    if _filter:
        filter_args = order_filter_parser.parse_args(req=args)
        order_no = filter_args.pop('order_no')
        if order_no:
            query = query.filter(Order.order_no.like('%' + order_no + '%'))

        for k, v in filter_args.items():
            if v is not None:
                query = query.filter(getattr(Order, k) == v)

        date_filter_args = date_filter_parser.parse_args(req=args)
        start_date = date_filter_args.get('start_date')
        end_date = date_filter_args.get('end_date')
        if start_date:
            if end_date is None:
                end_date = start_date
            query = query.filter((func.date(Order.order_time)).between(start_date, end_date))

    orders = query.all()

    return jsonify({
        'code': 0,
        'message': '成功',
        'data': marshal(orders, order_fields)
    }), 200


@auth.login_required
@roles_accepted('admin')
def refund(order_id):
    order = Order.query.get(order_id)
    if not order:
        raise APIException(ORDER_NOT_EXISTS)
    if order.status != 1:
        raise APIException(ORDER_NOT_EXISTS)
    goods = Goods.query.get(order.goods_id)
    info = GoodsInfo.query.filter_by(goods_id=order.goods_id, branch_id=order.branch_id).first()
    if not goods or goods.deleted or info is None:
        raise APIException(GOODS_NOT_EXISTS)
    user = order.user
    if not user:
        raise APIException(USER_NOT_EXISTS)
    # 开始退款 退回库存 退回销量 退回用户娃娃 写记录
    if order.order_sku:  # 有规格属性订单
        sku_stock = GoodsSkuStock.query.filter_by(goods_info_id=info.id).filter_by(sku_id=order.order_sku.sku_id).first()
        sku_stock.stock += order.order_sku.quantity
        sku_stock.exchange_num -= order.order_sku.quantity
        sku_stock.update(False,)
    # 更新分店商品库存及兑换数
    info.stock += order.amount
    info.exchange_num -= order.amount
    info.update(False, )
    # 更新商品的总兑换数（包括所有分店）
    goods.total_num -= order.amount
    goods.update(False, )
    # 更新用户娃娃数
    user.doll = user.doll - order.total_price
    user.update(False, )
    # 插入用户娃娃变更记录
    record_row = {
        'user_id': user.id,
        'type': 4,
        'doll': order.total_price,
        'branch_id': order.branch_id
    }
    UserRecord.create(False, **record_row)
    # 更新订单状态7：已退款
    order.update(False, status=7)
    try:
        db.session.commit()
    except Exception as e:
        db.session.rollback()
        raise APIException(DATABASE_ERROR)
    return jsonify({
        'code': 0,
        'message': '成功',
        'data': []
    }), 200


@auth.login_required
@roles_accepted('admin')
def add_attr_key():
    """ 添加属性key值"""

    args = add_attr_args.parse_args()

    attr = Attribute.query.filter_by(name=args['name']).first()

    if attr:
        raise APIException(ATTR_ALREADY_EXISTS)

    attr = Attribute.create(**args)
    return jsonify({
        'code': 0,
        'message': '添加成功',
        'data': marshal(attr, attr_fields)
    }), 200


@auth.login_required
@roles_accepted('admin')
def add_attr_value(k_id):
    """ 添加属性value值"""

    args = add_attr_args.parse_args()

    attr = Attribute.query.get(k_id)

    if not attr:
        raise APIException(ATTR_NOT_EXISTS)

    value = AttributeValue.query.filter_by(name=args['name']).first()

    if value:
        raise APIException(ATTR_VALUE_ALREADY_EXISTS)

    row = {
        'attribute_id': attr.id,
        'name': args['name']
    }

    attr_value = AttributeValue.create(**row)
    return jsonify({
        'code': 0,
        'message': '添加成功',
        'data': marshal(attr_value, attr_value_fields)
    }), 200


@auth.login_required
@roles_accepted('admin')
def update_infos():
    # 批量添加或更新goods_info
    args = update_infos_args.parse_args()

    infos = args.get('infos', [])
    for info in infos:
        info_id = info.get('id', 0)
        increment = info.get('add_stock', 0)
        if info_id:
            # 更新
            old_info = GoodsInfo.query.get(info['id'])
            row = {
                'goods_id': info['goods_id'],
                'branch_id': info['branch_id'],
                'is_listing': info['is_listing'],
                'recommended': info['recommended'],
                'weights': info['weights'],
                'stock': info.get('add_stock', 0) + old_info.stock
            }
            stock = 0
            total_stock = 0

            if info['sku_stock']:
                for item in info['sku_stock']:
                    stock_id = item.get('id', 0)
                    if stock_id:
                        goods_sku_stock = GoodsSkuStock.query.get(stock_id)
                        goods_sku_stock.stock += item['add_stock']
                        goods_sku_stock.update(False, )
                        stock += item['add_stock']
                        total_stock += goods_sku_stock.stock
                    else:
                        stock_row = {
                            'goods_info_id': info_id,
                            'sku_id': item['sku_id'],
                            'stock': item['add_stock']
                        }
                        GoodsSkuStock.create(False, **stock_row)
                        stock += item['stock']
                        total_stock += item['stock']

            if stock > 0:
                row['stock'] = total_stock
                increment = stock

            old_info.update(False, **row)

            old_tids = [tag.id for tag in old_info.tags]

            insert_tids = list(set(info['tids']).difference(set(old_tids)))

            delete_tids = list(set(old_tids).difference(set(info['tids'])))

            for tid in insert_tids:
                sql = 'insert into t_goods_info_tags values ({}, {})'.format(old_info.id, tid)
                db.session.execute(sql)
            for tid in delete_tids:
                sql = 'delete from t_goods_info_tags where goods_info_id = {} and tag_id = {}'.format(old_info.id, tid)
                db.session.execute(sql)

            record_row = {
                'stock_id': info['id'],
                'type': 1,
                'increment': increment
            }

            GoodsRecord.create(False, **record_row)
        else:
            # 创建
            row = {
                'goods_id': info['goods_id'],
                'branch_id': info['branch_id'],
                'is_listing': info['is_listing'],
                'recommended': info['recommended'],
                'weights': info['weights'],
                'stock': info['stock']
            }
            increment = info['stock']
            new_info = GoodsInfo.create(False, **row)
            stock = 0

            if info['sku_stock']:
                for item in info['sku_stock']:
                    stock_row = {
                        'goods_info_id': new_info.id,
                        'sku_id': item['id'],
                        'stock': item['add_stock']
                    }
                    GoodsSkuStock.create(False, **stock_row)
                    stock += item['add_stock']

            if stock > 0:
                new_info.update(False, stock=stock)
                increment = stock

            for tid in info['tids']:
                sql = 'insert into t_goods_info_tags values ({}, {})'.format(new_info.id, tid)
                db.session.execute(sql)

            record_row = {
                'stock_id': new_info.id,
                'type': 1,
                'increment': increment
            }

            GoodsRecord.create(False, **record_row)

    try:
        db.session.commit()
    except Exception as e:
        db.session.rollback()
        raise APIException(DATABASE_ERROR)

    return jsonify({
       'code': 0,
       'message': '成功',
       'data': []
    }), 200
